#include "StdAfx.h"
Mesh::Mesh(MeshDesc &desc):GameResource(desc)
{
}
Mesh::~Mesh(void)
{
}
void Mesh::LoadFromFile()
{
	LoadASE();
	CalculateNormals();
	InitLists();
}
void Mesh::SaveToFile()
{
}
float Mesh::GetRadius()
{
	return Radius;
}
void Mesh::LoadASE()
{
	sptr<SubMesh> submesh;
	int nVertices, nFaces;
	std::string::const_iterator bound;
	Vec3 vtemp, vpos;
	vmin=Vec3(0,0,0);
	vmax=Vec3(0,0,0);
	Mat33 mtransform;
	Reader reader(FileName);
	//enter next submesh
	while(reader.JumpAfterNext("GEOMOBJECT"))
	{
		reader.JumpAfterNext("NODE_TM");
		//get the name of the submesh
		reader.JumpAfterNext("NODE_NAME");
		//generate a new submesh
		BaseDesc desc;
		desc.Name=reader.GetQuotedString();
		submesh=sptr<SubMesh>(new SubMesh(desc));
		//get the matrix transform
		reader.JumpAfterNext("TM_ROW0");
		mtransform.setRow(0, reader.GetVec3());
		reader.JumpAfterNext("TM_ROW1");
		mtransform.setRow(1, reader.GetVec3());
		reader.JumpAfterNext("TM_ROW2");
		mtransform.setRow(2, reader.GetVec3());
		//get the position
		reader.JumpAfterNext("TM_ROW3");
		vpos=reader.GetVec3();
		//get buffer sizes
		reader.JumpAfterNext("MESH_NUMVERTEX");
		nVertices=reader.GetInt();
		submesh->Vertices.reserve(nVertices);
		//get index buffer size
		reader.JumpAfterNext("MESH_NUMFACES");
		nFaces=reader.GetInt();
		submesh->Indices.reserve(nFaces*3);
		//bounding shape values
		//get the vertices
		for(int i=0;i<nVertices;i++)
		{
			reader.JumpAfterNext("MESH_VERTEX");
			reader.GetInt();
			//fetch and transform the vertices
			vtemp=reader.GetVec3()-vpos;
			std::swap(vtemp.z, vtemp.y);
			vtemp.z=-vtemp.z;
			submesh->Vertices.push_back(vtemp);
			//store extremities
			vmin=vMin(vmin, vtemp);
			vmax=vMax(vmax, vtemp);
		}

		//compute radius
		Radius=std::max(std::max(vmax.x, vmax.y), vmax.z);
		//get the indices
		for(int i=0;i<nFaces;i++)
		{
			reader.JumpAfterNext("MESH_FACE");
			reader.JumpAfterNext(":");
			for(unsigned int j=0;j<3;j++)
				submesh->Indices.push_back(reader.GetInt());
		}
		//get the texCoords
		reader.JumpAfterNext("MESH_NUMTVERTEX");
		nVertices=reader.GetInt();
		vtemp.z=0;
		for(int i=0;i<nVertices;i++)
		{
			reader.JumpAfterNext("MESH_TVERT");
			vtemp.x=reader.GetReal();
			vtemp.y=1-reader.GetReal();
			submesh->TexCoords.push_back(vtemp);
		}		
		int diff=submesh->Vertices.size()-submesh->TexCoords.size();
		for(int i=0;i<diff;i++)
			submesh->TexCoords.push_back(Vec3());
		SubMeshes.push_back(submesh);
	}
}
//calculate the normals
void Mesh::CalculateNormals()
{
	for(unsigned int i=0;i<SubMeshes.size();i++)
	{
		sptr<SubMesh> submesh=SubMeshes[i];
		//reserve the normals vector
		submesh->Normals=std::vector<Vec3>(submesh->Vertices.size(), Vec3(0,0,0));
		submesh->Tangents=std::vector<Vec3>(submesh->Vertices.size(), Vec3(0,0,0));
		submesh->Bitangents=std::vector<Vec3>(submesh->Vertices.size(), Vec3(0,0,0));
		//compute the normals
		for(unsigned int j=0;j<submesh->Indices.size()-2;j+=3)
		{
			//get 2 vectors spanning the triangle plane
			Vec3 edge_1=-submesh->Vertices[submesh->Indices[j]]+submesh->Vertices[submesh->Indices[j+1]];
			Vec3 edge_2=-submesh->Vertices[submesh->Indices[j]]+submesh->Vertices[submesh->Indices[j+2]];
			//get 2 texcoord vectors along the edges
			Vec3 tedge_1=submesh->TexCoords[submesh->Indices[j]]-submesh->TexCoords[submesh->Indices[j+1]];
			Vec3 tedge_2=submesh->TexCoords[submesh->Indices[j]]-submesh->TexCoords[submesh->Indices[j+2]];
			//compute the normal
			Vec3 normal=edge_1.cross(edge_2);
			Vec3 tangent((tedge_2.y * edge_1.x - tedge_1.y * edge_2.x), 
						 (tedge_2.y * edge_1.y - tedge_1.y * edge_2.y),
						 (tedge_2.y * edge_1.z - tedge_1.y * edge_2.z));
			Vec3 bitangent=tangent.cross(normal);

			normal.normalize();
			tangent.normalize();
			bitangent.normalize();
			//add the normal to the 3 vertices spanning the triangle
			for(unsigned int k=0;k<3;k++)
			{
				submesh->Normals[submesh->Indices[j+k]]+=normal;
				submesh->Tangents[submesh->Indices[j+k]]+=bitangent;
				submesh->Bitangents[submesh->Indices[j+k]]-=tangent;
			}
		}
		//normalize the normals
		for(unsigned int j=0;j<submesh->Vertices.size();j++)
		{
			submesh->Normals[j].normalize();
			submesh->Tangents[j].normalize();
			submesh->Bitangents[j].normalize();
		}
	}
}
void Mesh::Draw(unsigned int subMeshId)
{
	if(subMeshId<SubMeshes.size()
		&&subMeshId>=0)
		DrawSubmesh(subMeshId);
}
void Mesh::Draw()
{
	for(unsigned int i=0;i<SubMeshes.size();i++)
		DrawSubmesh(i);
}
void Mesh::DrawSubmesh(unsigned int subMeshId)
{
	sptr<SubMesh> submesh=SubMeshes[subMeshId];
	glCallList(submesh->DrawList);
}
void Mesh::DebugDraw()
{
	for(unsigned int i=0;i<SubMeshes.size();i++)
		DebugDrawSubmesh(i);
}
void Mesh::DebugDraw(unsigned int subMeshId)
{
	if(subMeshId<SubMeshes.size()
		&&subMeshId>=0)
		DebugDrawSubmesh(subMeshId);
}
void Mesh::DebugDrawSubmesh(unsigned int subMeshId)
{
	sptr<SubMesh> submesh=SubMeshes[subMeshId];
	glCallList(submesh->DebugDrawList);
}
void Mesh::InitLists()
{
	for(unsigned int i=0;i<SubMeshes.size();i++)
	{
		sptr<SubMesh> submesh=SubMeshes[i];
		submesh->DrawList=glGenLists(1);
		glNewList(submesh->DrawList, GL_COMPILE);
			glBegin(GL_TRIANGLES);
			for(unsigned int j=0;j<submesh->Indices.size();j++)
				{
					int id=submesh->Indices[j];
					TexCoord(submesh->TexCoords[id],0);
					TexCoord(submesh->Tangents[id],1);
					TexCoord(submesh->Bitangents[id],2);
					Normal(submesh->Normals[id]);
					Vertex(submesh->Vertices[id]);
				}
			glEnd();
		glEndList();
		glNewList(submesh->DebugDrawList, GL_COMPILE);
			glBegin(GL_LINES);
			for(unsigned int i=0;i<submesh->Vertices.size();i++)
			{
				glColor4f(1,0,0,1);
				Vertex(submesh->Vertices[i]);
				Vertex(submesh->Vertices[i]+submesh->Normals[i]);
				glColor4f(0,1,0,1);
				Vertex(submesh->Vertices[i]);
				Vertex(submesh->Vertices[i]+submesh->Tangents[i]);
				glColor4f(0,0,1,1);
				Vertex(submesh->Vertices[i]);
				Vertex(submesh->Vertices[i]+submesh->Bitangents[i]);				
			}
			glColor4f(1,1,1,1);
			glEnd();
		glEndList();
	}
}
